﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using Tensop.Net.Core;
namespace Tensop.Net.Server
{
    public class TcpServer
    {
        ConnectionFactory           factory;
        IOCPBase                    _Iocp;
        
        Semaphore                   _wait;
        Socket                      _server;
        IPEndPoint                  _local;

        ProtocolManager             _parser;

        int                         maxConnection;
        int                         currentConnection;

        public event ServerFileReceiveEventHandler                  OnFileReceived;
        public event AtServerClientDisconnect                       OnClientDisconnected;

        /// <summary>
        /// 获取或接受一个值，当接收的数据长度大于或等于该值时则认定为文件
        /// </summary>
        public int FileSize { get; set; }

        public TcpServer(int max, IPEndPoint local, int filesize = 4096)
        {
            _wait = new Semaphore( max, max );
            _server = new Socket( _local.AddressFamily, SocketType.Stream, ProtocolType.Tcp );            
            _local = local;
            _Iocp = new IOCPBase( max );
            maxConnection = max;
            factory = new ConnectionFactory( max, _Iocp );
            
            _server.Bind( local );
            _server.Listen( 32 );
            FileSize = filesize;
        }

        public void Init()
        {
            factory.Init();
            _Iocp._OnAccept += OnAccept;
            _Iocp._OnDisconnect += OnDisconnect;
            _Iocp._OnReceive += OnReceive;
            _Iocp._OnSend += OnSend;
        }

        public void Start(IProtocolHeaderParser parser)
        {
            _parser = new ProtocolManager( parser );
            StartAccept( null );
        }

        private void StartAccept(SocketAsyncEventArgs e)
        {
            if ( e == null )
            {
                e = new SocketAsyncEventArgs();
                e.Completed += OnAccept;
            }
            else
            {
                e.AcceptSocket = null;
            }
            _wait.WaitOne();
            _server.AcceptAsync( e );
        }
        private void OnAccept(object sender, SocketAsyncEventArgs e)
        {
            OnAccept( e.AcceptSocket );
            StartAccept( e );
        }

        private void OnSend(ConnectionContext cc)
        {

        }

        private void OnReceive(ConnectionContext cc, byte[] data)
        {
            if ( data.Length < FileSize )
            {
                var result = _parser.Parse( data, cc );
                factory.Send( cc, result );
            }
            else
            {
                OnFileReceived?.Invoke( cc, data );
            }
        }

        private void OnDisconnect(ConnectionContext cc)
        {
            var e = factory[cc];
            var id = cc.Id;
            var userToken = cc.UserToken;
            factory.Push( e );
            OnClientDisconnected?.Invoke( id, userToken );
        }

        private void OnAccept(Socket s)
        {
            if ( !s.Connected )
                return;
            var e = factory[factory.Pop(), s];
            factory.Receive( e );//开始接收数据
            Interlocked.Increment( ref currentConnection );
        }
    }
}
